/*
 * Copyright (C) 2011 Moritz Schmale <narrow.m@gmail.com>
 *
 * DropChest is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl.html>.
 */

package me.scotty86.DropChest;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

//import net.milkbowl.vault.permission.Permission;


import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.yaml.snakeyaml.Yaml;

public class DropChest extends JavaPlugin {
	/* Config settings */
	public Configuration config;

	private List<DropChestItem> chests = new ArrayList<DropChestItem>();
	private Map<Integer, DropChestItem> chestsHashInteger = new HashMap<Integer, DropChestItem>();
	private Map<String, DropChestItem> chestsHashName = new HashMap<String, DropChestItem>();
	private Map<Integer, DropChestItem> chestsHashBlocks = new HashMap<Integer, DropChestItem>();

	private DropChestPlayerListener playerListener;
	private DropChestBlockListener blockListener;
	private DropChestWorldListener worldListener;
	private DropChestVehicleListener vehicleListener;
	private EntityWatcher entityWatcher;

	private final HashMap<Player, Boolean> debugees = new HashMap<Player, Boolean>();

	public Logger log;
	private int watcherid;
	
	public DropChest() {
		// TODO: Unschoen, muss raus
		DropChestPlayer.plugin = this;
	}

	public void onEnable() {
		this.log = getServer().getLogger();

		//Read configuration
		File settings = new File(getDataFolder().getAbsolutePath() + "/dropchest.cfg");
		this.config = new Configuration(settings);

		this.playerListener = new DropChestPlayerListener(this);
		this.blockListener = new DropChestBlockListener(this);
		this.worldListener = new DropChestWorldListener(this);
		this.vehicleListener = new DropChestVehicleListener(this);

		// Register our events
		PluginManager pm = getServer().getPluginManager();
		pm.registerEvents(this.blockListener, this);
		pm.registerEvents(this.playerListener, this);
		pm.registerEvents(this.vehicleListener, this);
		pm.registerEvents(this.worldListener, this);

		//Register the Entity Watcher
		this.entityWatcher = new EntityWatcher(this);
		this.watcherid = getServer().getScheduler().scheduleSyncRepeatingTask(this, this.entityWatcher, 10L, 10L);

		//Read plugin file
		PluginDescriptionFile pdfFile = getDescription();
		this.log.log(Level.INFO, pdfFile.getName() + " version " + pdfFile.getVersion() + " is enabled!");

		// Load our stuff
		load();
	}

	public void addChest(DropChestItem item) {
		this.chestsHashInteger.put(Integer.valueOf(item.getId()), item);
		this.chestsHashName.put(item.getName(), item);
		this.chestsHashBlocks.put(item.getBlock().getLocation().hashCode(), item);
		this.chests.add(item);

		DropChestPlayer player = item.getOwnerDCPlayer();
		player.addChest(item);
		save();
	}

	private void load() {
		File dir = getDataFolder();
		if (!dir.exists()) {
			this.log.log(Level.INFO, "DropChest directory does not exist. Creating on next save!");
			return;
		}
		
		File yamlFile = new File(dir, "dropchests.yml");
		if (yamlFile.exists()) {
			Yaml yaml = new Yaml();
			try {
				FileReader reader = new FileReader(yamlFile);
				@SuppressWarnings("unchecked")
				Map<String, Object> chests = (Map<String, Object>) yaml.load(reader);
				
				
				for (Object chest:chests.values()) {
					@SuppressWarnings("unchecked")
					Map<String, Object> chestconv = (Map<String, Object>) chest;
					DropChestItem item = new DropChestItem(chestconv, this);
					
					//log.log(Level.INFO, "Chest #" + item.getId() + " loaded.");
					
					if (item.isLoadedProperly())
					{
						addChest(item);
					}
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			return;
		}
	}

	public void save() {
		File dir = getDataFolder();
		if (!dir.exists()) {
			this.log.log(Level.INFO, "Creating DropChest directory.");
			dir.mkdir();
		}
		File file = new File(dir.getAbsolutePath() + "/dropchests.yml");
		if (!file.exists()) {
			this.log.log(Level.INFO, "no file. Trying to create it.");
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
				return;
			}
		}
		try {
			Map<String, Object> data = new HashMap<String, Object>();
			for (DropChestItem dci : getChests()) {
				Map<String, Object> chest = new HashMap<String, Object>();
				dci.save(chest);
				data.put(Integer.toString(dci.getId()), chest);
			}
			Yaml yaml = new Yaml();
			FileWriter writer = new FileWriter(file);
			yaml.dump(data, writer);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public boolean isDebugging(Player player) {
		if (this.debugees.containsKey(player)) {
			return this.debugees.get(player);
		}
		return false;
	}

	public void setDebugging(Player player, boolean value) {
		this.debugees.put(player, value);
	}

	@Override
	public void onDisable() {
		getServer().getScheduler().cancelTask(this.watcherid);
		save();
	}

	public Boolean isNear(Location loc1, Location loc2, double maxDistance) {
		if (loc1.getWorld().getUID() != loc2.getWorld().getUID()) {
			return Boolean.valueOf(false);
		}
		double x1 = loc1.getX(), x2 = loc2.getX();
		double y1 = loc1.getY(), y2 = loc2.getY();
		double z1 = loc1.getZ(), z2 = loc2.getZ();
		double dx = x1 - x2;
		double dy = y1 - y2;
		double dz = z1 - z2;
		double maxDistance2 = maxDistance * maxDistance;
		double distance2 = dx * dx + dy * dy + dz * dz;
		
		return (distance2 <= maxDistance2);
	}

	//@SuppressWarnings("deprecation")
	@Override
	public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
		Player player = null;
		DropChestPlayer dplayer = null;
		
		if (sender.getClass().getName().contains("Player")) {
			player = (Player) sender;
			dplayer = DropChestPlayer.getPlayerByName(player.getName());
		}
		
		if (cmd.getName().equals("dropchest")) {
			boolean syntaxerror = false;
			
			// no permission to use dc
			if (!hasPermission(player, "dropchest")) {
				player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use DropChest. Please ask your Operator to enable this awesome plugin for you.");
				return true;
			}
			
			if (args.length == 0) {
				syntaxerror = true;
			} else if (args[0].equalsIgnoreCase("add")) {
				/*****************
                 *        ADD     *
                 *****************/
				if (!hasPermission(player, "create")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to create DropChests.");
					return true;
				}
				DropChestPlayer player2 = DropChestPlayer.getPlayerByName(player.getName());
				player2.setChestRequestType(ChestRequestType.CREATE);
				int requestedRadius = this.config.getDefaultRadius();
				if (args.length == 2) 
				{
					if(hasPermission(player, "radius.set"))
					{
						requestedRadius = Integer.valueOf(args[1]).intValue();
						if ((requestedRadius > getMaximumRadius(player)) && (!hasPermission(player, "radius.setBig"))) {
							player.sendMessage(ChatColor.DARK_RED + "Radius too big.");
							return true;
						}
					}
					else
					{
						player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to set the radius.");
						return true;
					}
				}
				player2.setRequestedRadius(requestedRadius);
				requestedRadius = this.config.getDefaultRadius();
				sender.sendMessage(ChatColor.GREEN.toString() + "Now rightclick on the Chest that you want to add");
			} else if (args[0].equalsIgnoreCase("remove")) {
				/*****************
                 *       REMOVE *
                 *****************/
				if (!hasPermission(player, "remove")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to remove DropChests.");
					return true;
				}
				
				if (args.length == 2) {
					DropChestItem dci = getChestByIdOrName(args[1]);
					if (dci != null) {
						// Is it allowed to remove the chest?
						if ((ownsChest(dci, sender)) || (hasPermission(player, "remove.others"))) {
							removeChest(dci);
							save();
							sender.sendMessage(ChatColor.GREEN.toString() + "Removed Chest.");
						} else {
							sender.sendMessage(ChatColor.DARK_RED + "You do not have permissions to remove DropChests of other players.");
							return true;
						}
					} else
						sender.sendMessage(ChatColor.RED + "Dropchest not found.");
				} else {
					syntaxerror = true;
				}
			} else if (args[0].equalsIgnoreCase("list")) {
                /*****************
                 *        LIST   *
                 *****************/
				if (!hasPermission(player, "list")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to list DropChests.");
					return true;
				}
				
				int i = 1;
				//Page limit is 6 items per page
                //calculation of needed pages
				List<DropChestItem> chests;
				if ((dplayer != null) && ((args.length <= 2) || (!args[2].equals("all"))))
				{
					chests = dplayer.getChests();
				}
				else
				{
					chests = this.chests;
				}
				
				int num = chests.size();
				int needed = (int) Math.ceil(num / 6.0D);
				int current = 1;
				if (args.length == 2) {
					current = Integer.valueOf(args[1]);
				}
				if (current > needed)
					current = 1;
				if (needed != 1) {
					sender.sendMessage(ChatColor.BLUE.toString() + "Page "
							+ String.valueOf(current) + " of "
							+ String.valueOf(needed));
				}
				sender.sendMessage(ChatColor.BLUE.toString()
						+ "Name | % full | filters | radius");
				sender.sendMessage(ChatColor.BLUE.toString() + "------");
				for (i = (current - 1) * 6; i < Math.min(current * 6, chests.size()); i++) {
					sender.sendMessage(((DropChestItem) chests.get(i)).listString());
				}
			} else if (args[0].equalsIgnoreCase("tp")) {
                /*****************
                 *   TELEPORT   *
                 *****************/
				if (!hasPermission(player, "teleport")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to teleport to DropChests.");
					return true;
				}

				DropChestItem dci = getChestByIdOrName(args[1]);
				if (dci != null)
				{
					if ((player != null) && ((ownsChest(dci, player)) || (hasPermission(player, "teleport.others")) ))
					{
						player.teleport(dci.getBlock().getLocation());
					}
					else
					{
						player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to teleport to DropChests of other players.");
						return true;
					}
				} else
					sender.sendMessage(ChatColor.RED.toString() + "This chest does not exist.");
			} else if (args[0].equalsIgnoreCase("setradius")) {
                /*****************
                 *   SETRADIUS   *
                 *****************/
				if (!hasPermission(player, "radius.set")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to set the radius.");
					return true;
				}
				if (args.length == 3) {
					int radius = Integer.valueOf(args[2]);
					DropChestItem dci = getChestByIdOrName(args[1]);
					if (dci != null) {
						if (ownsChest(dci, sender) || (hasPermission(player, "radius.others"))) {
							
							if ((radius > getMaximumRadius(player)) && ((!hasPermission(player, "radius.setBig")) || (this.config.isMod(player))))
							{
								player.sendMessage(ChatColor.DARK_RED + "Radius too big.");
								return true;
							}
							
							dci.setRadius(radius);
							sender.sendMessage(ChatColor.GREEN + "Radius of Chest #" + dci.getId() + " set to " + String.valueOf(dci.getRadius()));
							save();
						} else {
							player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to change the radius of DropChests of other players.");
							return true;
						}
					} else
						syntaxerror = true;
				} else {
					syntaxerror = true;
				}
			} else if (args[0].equalsIgnoreCase("setdelay")) {
                /*****************
                 *   SETDELAY   *
                 *****************/
				if (!hasPermission(player, "delay")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to change the radius of DropChests of other players.");
					return true;
				}
				if (args.length == 3) {
					int delay = Integer.valueOf(args[2]).intValue(); 
					delay = delay > 0 ? delay : 0; //Derp derp, I'll set a negative delay! Nope.
					DropChestItem dci = getChestByIdOrName(args[1]);
					if (dci != null) {
						if (ownsChest(dci, sender) || hasPermission(player, "delay.others")) {
							dci.setDelay(delay);
							sender.sendMessage(ChatColor.GREEN
									+ "Delay of Chest '" + dci.getName()
									+ "' set to "
									+ String.valueOf(dci.getDelay())
									+ " milliseconds.");
							save();
						} else {
							player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to change the delay of DropChests of other players.");
							return true;
						}
					} else
						syntaxerror = true;
				} else {
					syntaxerror = true;
				}
			} else if (args[0].equalsIgnoreCase("which")) {
                /*****************
                 *       WHICH   *
                 *****************/
				if (!hasPermission(player, "which")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use which.");
					return true;
				}
				if (player != null) {
					DropChestPlayer pl = DropChestPlayer.getPlayerByName(player.getName());
					pl.setChestRequestType(ChestRequestType.WHICH);
					sender.sendMessage(ChatColor.GREEN.toString() + "Now rightclick on a chest to get its properties.");
				}
			} else if (args[0].equalsIgnoreCase("filter")) {
				/*****************
                 *       FILTER *
                 *****************/
				//dropchest filter {suck|push|pull|finish} [{chestid} {itemid|itemtype|clear}]
				if (!hasPermission(player, "filter")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use filter.");
					return true;
				}
				if (args.length == 4)
				{
					String typestring = args[1];
					FilterType type = null;
					try {
						type = FilterType.valueOf(typestring.toUpperCase());
					} catch (IllegalArgumentException e) {
						type = null;
					}
					
					if(type == FilterType.valueOf("SUCK"))
					{
						if (!hasPermission(player, "filter.suck")) {
							player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use the SUCK-filter.");
							return true;
						}
					}
					if(type == FilterType.valueOf("PUSH"))
					{
						if (!hasPermission(player, "filter.push")) {
							player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use the PUSH-filter.");
							return true;
						}
					}
					if(type == FilterType.valueOf("PULL"))
					{
						if (!hasPermission(player, "filter.pull")) {
							player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use the pull-filter.");
							return true;
						}
					}
					
					if (type != null)
					{
						DropChestItem chest = getChestByIdOrName(args[2]);
						if(chest != null)
						{
							if(ownsChest(chest, sender) || hasPermission(player, "filter.others"))
							{
								String itemstring = args[3];
								FilterItem item = null;
								if (itemstring.equalsIgnoreCase("clear"))
								{
									chest.getFilter(type).clear(); //filter gets cleared by setFilterAll
									sender.sendMessage(ChatColor.GREEN + "Filter cleared.");
								}
								else if (itemstring.equalsIgnoreCase("all"))
								{
										List<FilterItem> filter = chest.getFilter(type);
										chest.getFilter(type).clear();
										filter.add(FilterItem.allItem);
										sender.sendMessage(ChatColor.GREEN + "All items now being "+ type.toString().toLowerCase() + "ed.");
								}
								else
								{
									try
									{
										item = new FilterItem(itemstring);
									}
									catch (Exception e)
									{
										
									}
									
									if (item != null)
									{
										List<FilterItem> filter = chest.getFilter(type);
										
										// If all-Filter is active, it has to be disabled, if you want to filter a specific item
										if (filter.contains(FilterItem.allItem))
											filter.remove(FilterItem.allItem);
										/*
										if(chest.getFilterAll(type) == true)
											chest.setFilterAll(type, false);
										*/
										
										if (item.isContained(filter))
										{
											item.removeFromList(filter);
											sender.sendMessage(ChatColor.GREEN + item.getDisplayName() + " is no more being " + type.toString().toLowerCase() + "ed.");
										}
										else
										{
											// Cleaning up
											for (Iterator<FilterItem> iterator = filter.iterator(); iterator.hasNext(); )
											{
												FilterItem tmpItem = iterator.next();
												if(tmpItem.getTypeID() == item.getTypeID())
												{
													if(item.getDataID() == -1)
													{
														iterator.remove();
													}
													else
													{
														if(tmpItem.getDataID() == -1)
														{
															iterator.remove();
															break;
														}
													}
												}
										    }
											filter.add(item);
											sender.sendMessage(ChatColor.GREEN + item.getDisplayName() + " is now being " + type.toString().toLowerCase() + "ed.");
										}
									}
									else
									{
										sender.sendMessage(ChatColor.RED + "Material " + itemstring + " not found.");
										return true;
									}
								}
								save();
							}
							else
							{
								sender.sendMessage(ChatColor.DARK_RED + "You do not have permissions to change the filter of DropChests of other players.");
								return true;
							}
						}
						else
						{
							sender.sendMessage(ChatColor.RED + "No such chest " + args[1] + ".");
							return true;
						}
					} 
					else
					{
						sender.sendMessage(ChatColor.RED + "Filter type not found.");
						return true;
					}
				}
				else
				{
					sender.sendMessage(ChatColor.RED + "Syntax error:");
					sender.sendMessage(ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " filter {suck|push|pull} {chest} {itemid|itemtype|clear|all}");
					return true;
				}
			} else if (args[0].equalsIgnoreCase("setname")) {
                /*****************
                 *      SETNAME *
                 *****************/
				if (!hasPermission(player, "setname")) {
					player.sendMessage(ChatColor.DARK_RED + "You do not have permissions to use setname.");
					return true;
				}
				
				if (args.length == 3) {
					String name = args[2];
					DropChestItem item = getChestByIdOrName(args[1]);
					if (item != null)
						if (ownsChest(item, sender) || hasPermission(player, "setname.others")) {
							item.setName(name);
							sender.sendMessage(ChatColor.GREEN + "Set name of Chest #" + item.getId() + " to " + item.getName());
							//sender.sendMessage(ChatColor.GREEN + "Radius of Chest #" + dci.getId() + " set to " + String.valueOf(dci.getRadius()));
							updateName(item);
							save();
						} else {
							sender.sendMessage(ChatColor.DARK_RED + "You do not have permissions to change the name of DropChests of other players.");
							return true;
						}
				} else {
					syntaxerror = true;
				}
			} else if (args[0].equalsIgnoreCase("protect")) {
                /*****************
                 *      Protect *
                 *****************/
				if (args.length == 3) {
					String cheststring = args[1];
					String mode = args[2];
					DropChestItem item = getChestByIdOrName(cheststring);
					if (item == null) {
						sender.sendMessage("This chest does not exist.");
						return false;
					}
					if (!this.config.isLetUsersProtectChests()) {
						sender.sendMessage("Chest protection is disabled on this server.");
						return false;
					}
					boolean mayProtect = true;
					if ((sender instanceof Player)) {
						mayProtect = hasPermission((Player) sender, "dropchest.protect");
					}
					if ((ownsChest(item, sender)) && (mayProtect)) {
						if (mode.equalsIgnoreCase("off")) {
							item.setProtect(false);
							sender.sendMessage("Chest is not anymore protected.");
						} else if (mode.equalsIgnoreCase("on")) {
							item.setProtect(true);
							sender.sendMessage("Chest is now protected.");
						} else {
							syntaxerror = true;
						}
						save();
					} else {
						sender.sendMessage("You may not set this attribute.");
					}
				}
			} else if (args[0].equalsIgnoreCase("setowner")) {
                /*****************
                 *      setowner *
                 *****************/
				if (args.length == 3) {
					String cheststring = args[1];
					String newowner = args[2];
					DropChestItem item = getChestByIdOrName(cheststring);
					if (item == null) {
						sender.sendMessage("Chest not found.");
						return false;
					}
					if (ownsChest(item, sender)) {
						item.setOwner(newowner);
						save();
						sender.sendMessage("Owner of chest " + item.getId() + " set to " + newowner + ".");
					} else {
						sender.sendMessage("That's not your chest!");
					}
				} else {
					syntaxerror = true;
				}
			} else if (args[0].equalsIgnoreCase("info")) {
                /*****************
                 *      info *
                 *****************/
				if (args.length == 2) {
					DropChestItem chest = getChestByIdOrName(args[1]);
					if (chest != null) {
						if (ownsChest(chest, sender))
							sender.sendMessage(chest.info());
					} else
						sender.sendMessage("Chest not found.");
				}
			} else {
				this.log.log(Level.INFO, "Command not found.");
				syntaxerror = true;
			}

			if ((syntaxerror) && (onPermissionSend(sender, "dropchest", ChatColor.RED + "DropChest Commands:"))) {
				sender.sendMessage(ChatColor.GOLD + "{this} " + ChatColor.WHITE + "is a required variable argument");
				sender.sendMessage(ChatColor.GOLD + "[this=x] " + ChatColor.WHITE + "can be omitted, x is standard");
				sender.sendMessage(ChatColor.GOLD + "{chest} " + ChatColor.WHITE + "can be either a name or an id");
				onPermissionSend(sender, "create", 		ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " add [radius=2]");
				onPermissionSend(sender, "remove", 		ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " remove {chest}");
				onPermissionSend(sender, "list", 		ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " list [page=1]");
				//onPermissionSend(sender, "info", 		ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " info {chestname|chestid}");
				onPermissionSend(sender, "radius.set", 	ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " setradius {chest} {radius}");
				onPermissionSend(sender, "which", 		ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " which");
				onPermissionSend(sender, "teleport", 	ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " tp {chest}");
				onPermissionSend(sender, "filter", 		ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " filter {suck|push|pull} {chest} {itemid|itemtype|clear|all}");
				onPermissionSend(sender, "setname", 	ChatColor.GOLD + " /dropchest" + ChatColor.WHITE + " setname {chest} {name}");
				int max = getMaximumRadius(player);
				String maxs = String.valueOf(max);
				if ((hasPermission(player, "dropchest.radius.setBig")) || (max == 65536)) {
					maxs = "unlimited";
				}
				sender.sendMessage("Your maximum radius is: " + ChatColor.GOLD + maxs + ChatColor.WHITE + ".");
			}
		}
		/*
		if ((cmd.getName().equals("dcitem")) && (args.length == 1)) {
			int id = 0;
			Material m = null;
			try {
				id = Integer.valueOf(args[0]).intValue();
			} catch (Exception e) {
				m = Material.matchMaterial(args[0].toUpperCase());
			}
			if (id != 0) {
				m = Material.getMaterial(id);
				if (m != null)
					sender.sendMessage(ChatColor.YELLOW + Integer.toString(id) + ChatColor.WHITE + " is " + ChatColor.YELLOW + m.toString());
				else {
					sender.sendMessage(ChatColor.RED + "That item does not exist.");
				}
			} else if (m != null) {
				id = m.getId();
				sender.sendMessage(ChatColor.YELLOW + m.toString() + ChatColor.WHITE + " is " + ChatColor.YELLOW + id);
			} else {
				sender.sendMessage(ChatColor.RED + "That item does not exist.");
			}

			return true;
		}
		*/
		
		if (cmd.getName().equals("chestinfo")) {
			if (!hasPermission(player, "dropchest.moderator")) {
				sender.sendMessage("You may not use this command");
				return false;
			}
			if (args.length == 1) {
				DropChestItem dci = getChestByIdOrName(args[0]);
				if (dci == null) {
					sender.sendMessage("This chest doesn't exist.");
					return false;
				}
				String info = chestInformation(dci.getInventory(), "of " + dci.getName());
				if (dplayer != null)
					dplayer.sendMessage(info);
				else {
					sender.sendMessage(info);
				}
				return true;
			}
			if (dplayer != null) {
				dplayer.setChestRequestType(ChestRequestType.CHESTINFO);
				dplayer.sendMessage("Rightclick on any chest to get information");
			} else {
				sender.sendMessage("You can't use interactive commands from the console");
				return false;
			}
		}

		return false;
	}

	public int getChestCount() {
		return this.chests.size();
	}

	public void removeChest(DropChestItem dci) {
		this.chests.remove(dci);
		this.chestsHashBlocks.remove(Integer.valueOf(dci.getBlock().getLocation().hashCode()));
		this.chestsHashInteger.remove(Integer.valueOf(dci.getId()));
		this.chestsHashName.remove(dci.getName());
		dci.getOwnerDCPlayer().removeChest(dci);
	}

	public void updateName(DropChestItem dci) {
		this.chestsHashName.put(dci.getName(), dci);
	}

	public int getMaximumRadius(Player player) {
		if (this.config.isMod(player)) {
			return 65536;
		}
		return this.config.getMaxRadius();
	}

	public boolean hasPermission(Player player, String node) {
		 boolean ok = player.hasPermission("dropchest." + node);
		 /*
		 if (!ok) {
			 player.sendMessage(ChatColor.RED + "You do not have permissions to do that.");
		 }
		 */
		 return ok;
	}

	public boolean onPermissionSend(CommandSender sender, String node, String message) {
		Player player = null;
		if (sender.getClass().getName().contains("Player")) {
			player = (Player) sender;
		}
		if (hasPermission(player, node)) {
			sender.sendMessage(message);
			return true;
		}
		return false;
	}

	public Location locationOf(Block block) {
		return block.getLocation();
	}

	public boolean locationsEqual(Location loc1, Location loc2) {
		return loc1.equals(loc2);
	}

	public DropChestItem getChestByBlock(Block block) {
		return this.chestsHashBlocks.get(block.getLocation().hashCode());
	}

	public DropChestItem getChestById(int id) {
		return this.chestsHashInteger.get(id);
	}

	public DropChestItem getChestByIdOrName(String arg) {
		int id = 0;
		DropChestItem dci = null;
		try {
			id = Integer.valueOf(arg);
			dci = getChestById(id);
		} catch (Exception e) {
			dci = getChestByName(arg);
		}
		return dci;
	}

	public DropChestItem getChestByName(String name) {
		if (name.equals(""))
			return null;
		return (DropChestItem) this.chestsHashName.get(name);
	}

	// check if a player has owner rights
	public boolean ownsChest(DropChestItem dci, CommandSender sender) {
		// mods own everything!
		if (this.config.isMod(sender)) {
			return true;
		}

		// if the sender is a player
		if (((sender instanceof Player))
				&& (dci.getOwner().equals(sender.getName()))) {
			return true;
		}
		if (dci.getOwner().equals("")) {
			return true;
		}
		return false;
	}

	@SuppressWarnings("deprecation")
	public static String chestInformation(Inventory inv, String identifier) {
		HashMap<Material, Integer> map = new HashMap<Material, Integer>();
		int count;
		for (int i = 0; i < inv.getSize(); i++) {
			ItemStack stack = inv.getItem(i);
			if ((stack != null) && (stack.getTypeId() != 0)) {
				Material mat = stack.getType();
				count = Integer.valueOf(stack.getAmount());
				if (map.containsKey(mat)) {
					int excnt = ((Integer) map.get(mat)).intValue();
					count = Integer.valueOf(count + excnt);
				}
				map.put(mat, count);
			}
		}
		
		String ret = ChatColor.GREEN + "Statistics for inventory " + identifier
				+ ":\n";
		int i = 0;
		for (Material mat : map.keySet()) {
			count = map.get(mat);
			ret += ChatColor.YELLOW + mat.toString() + ChatColor.WHITE + ": " + count;
			if (i != map.size() - 1) {
				ret += "\n";
			}
			i++;
		}
		return ret;
	}

	public List<DropChestItem> getChests() {
		return Collections.unmodifiableList(this.chests);
	}

	public boolean chestExists(Block b) {
		return this.chestsHashBlocks.containsKey(b);
	}

	// Check if a player is allowed to use a chest
	public boolean hasRights(Block chest, Player player) {
		
		// Mods are gods ;)
		if (this.config.isMod(player)) {
			return true;
		}

		// check lockette-rights
		if (!hasLocketteRights(chest, player)) {
			return false;
		}
		return true;
	}

	/*
     * checks is a chest is protected by lockette and if the player is allowed
     * to use the chest
     * TODO: altPrivate (alternative private)
     * */
	public boolean hasLocketteRights(Block chest, Player player) {
		return hasLocketteRights(chest, player, false);
	}

	public boolean hasLocketteRights(Block chest, Player player, boolean isSecondChest) {
		// if no lockette compatibility is wished, do nothing
		if (!this.config.isLocketteCompatibilityActivated()) {
			return true;
		}
		boolean locketteSigneFound = false;

		// get all blocks around
		List<Block> blocks = new ArrayList<Block>();
		blocks.add(chest.getRelative(BlockFace.NORTH));
		blocks.add(chest.getRelative(BlockFace.EAST));
		blocks.add(chest.getRelative(BlockFace.SOUTH));
		blocks.add(chest.getRelative(BlockFace.WEST));
		Iterator<Block> blockIter = blocks.iterator();

		// iter all blocks
		while (blockIter.hasNext()) {
			// if type of a block around is a signe, check for rights
			Block currBlock = (Block) blockIter.next();

			if (currBlock.getType() == Material.WALL_SIGN) {
				Sign sign = (Sign) currBlock.getState();
				String text = sign.getLine(0).replaceAll("(?i)\u00A7[0-F]", "").toLowerCase();

				if ((text.equals("[private]")) || (text.equals("[more users]"))) {
					locketteSigneFound = true;
					String playername = player.getName().toLowerCase();
					for (int i = 1; i < 4; i++) {
						if ((sign.getLine(i) != null) && (playername.equals(sign.getLine(i)))) {
							return true;
						}
					}
				}
			}
			
			// If it is a doublechest, we have to check, if there is a signe at the second chest
			if ((currBlock.getType() == Material.CHEST)
					&& (!isSecondChest)
					&& (hasLocketteRights(currBlock, player, true))) {
				return true;
			}
		}

		// if it is the second chest and there is no signe signe for the player, we have to return false
		if (isSecondChest) {
			return false;
		}

		// if we found no lockette-signe, the player can use the chest
		if (locketteSigneFound) {
			return false;
		}
		return true;
	}

	// Find a DC around a block
	public DropChestItem findDropchestAround(Block chest) {
		List<Block> blocks = new ArrayList<Block>();
		blocks.add(chest.getRelative(BlockFace.NORTH));
		blocks.add(chest.getRelative(BlockFace.EAST));
		blocks.add(chest.getRelative(BlockFace.SOUTH));
		blocks.add(chest.getRelative(BlockFace.WEST));
		Iterator<Block> blockIter = blocks.iterator();

		// iter all blocks
		while (blockIter.hasNext()) {
			Block currBlock = (Block) blockIter.next();
			if (currBlock.getType() == Material.CHEST)
				return getChestByBlock(currBlock);
		}
		return null;
	}
	
	/*
	@SuppressWarnings("deprecation")
	static public MaterialData GetMaterialData(String itemstring)
	{
		MaterialData myOutput = null;
		
		if(StringUtils.countMatches(itemstring, ":") == 1)
		{
			String[] subIDs = itemstring.split(":");
			
			
			int itemid = -1;
			try {
				itemid = Integer.valueOf(subIDs[0]);
			} catch (NumberFormatException e) {
				return null;
			}
			
			int itemdata = -1;
			try {
				itemdata = Integer.valueOf(subIDs[1]);
			} catch (NumberFormatException e) {
				return null;
			}
			
			if((itemid != -1) && (itemdata != -1))
			{
				try {
					myOutput = new MaterialData(itemid, Byte.valueOf(String.valueOf(itemdata)));
				}
				catch (Exception e) {
					
				}
			}
		}
		else
		{
			int itemid = -1;
			try {
				itemid = Integer.valueOf(itemstring);
				myOutput = new MaterialData(itemid);
			} catch (NumberFormatException e) {
				
			}
		}
		
		//System.out.println("===> "+itemstring.toUpperCase()+" : ");
		
		if(myOutput == null)
		{
			try
			{
				Material tmp = Material.getMaterial(itemstring.toUpperCase());
				myOutput = new MaterialData(tmp.getId());
			}
			catch (Exception e)
			{
				
			}
		}
		
		return myOutput;
	}
	
	@SuppressWarnings("deprecation")
	static public MaterialData GetMaterialData(Material myInput)
	{
		return GetMaterialData(Integer.toString(myInput.getId()));
	}
	
	@SuppressWarnings("deprecation")
	static public String GetIDFromMaterialData(MaterialData myInput)
	{
		String myOutput = "";
		
		myOutput += myInput.getItemTypeId();
		if(myInput.getData() > 0)
		{
			myOutput += ":" + myInput.getData();
		}
		
		return myOutput;
	}
	
	@SuppressWarnings("deprecation")
	static boolean MaterialDataEquals(MaterialData in1, MaterialData in2)
	{
		if(in1.getItemTypeId() != in2.getItemTypeId())
			return false;
		
		if(in1.getData() != in2.getData())
			return false;
		
		return true;
	}
	*/
}